<template>
  <div class="map-components">
    <div id="container" class="container-box"></div>
    <div class="map-content">
      <van-popup
        class="map-popup"
        v-model="popupShow"
        position="bottom"
        overlay-class="map-content"
      >
        <div
          class="popup-item"
          v-for="(item) in popupData"
          :key="item.type"
          @click="popupItemClick(item)"
        >{{ item.name }}</div>
      </van-popup>
    </div>
  </div>
</template>

<script>
import { AMapBase, mapGeolocation, mapGetAddress, openNavigationApp, setInfoWindow, setMarker } from '@/utils/AMapBase'
import Vue from 'vue'

export default {
  name: 'AMapComponents',
  data () {
    return {
      map: null, // 保存地图初始化对象信息
      infoWindow: null, // 保存信息弹出对象信息
      markerList: [], // 点击后标记保存的信息 {regeocode: 当前点地图信息, marker: 标记构建实例}
      markerData: null, // 当前弹框显示的标记数据
      popupShow: false, // 导航列表展示
      popupData: [{ name: '腾讯地图', type: 'TX' }, { name: '百度地图', type: 'BD' }, { name: '高德地图', type: 'GD' }, { name: '苹果地图', type: 'PG' }]
    }
  },
  props: {
    // 默认展示地图到时候中心点,不传默认展示自身定位(显示优先权大于location,地图中心最终还是会定位到center) 格式[133.165,26.365]
    center: {
      type: Array,
      default: null
    },
    // 是否获取自身定位(展示自身定位圆点标记)
    location: {
      type: Boolean,
      default: true
    },
    // 是否加载默认自身标记(需要location为true)
    defaultModify: {
      type: Boolean,
      default: true
    },
    // 是否运行修改标记(点击添加标记操作)
    isModify: {
      type: Boolean,
      default: false
    },
    // 最大标记数(超过最大标记数则会先进先出覆盖标记),默认为1,true为无限,需配合isModify使用
    maxMarker: {
      type: [Number, Boolean],
      default: 1
    },
    // 默认展示标记的点 格式[title:'',lnglat:[133.126,26.365]]
    defalutModifyList: {
      type: Array,
      default: () => []
    },
    // 是否需要默认弹框
    isInfoWindow: {
      type: Boolean,
      default: true
    },
    // 标记点击是否默认展示出弹框
    showInfoWindw: {
      type: Boolean,
      default: true
    },
    // 弹框定位,可选值top,right,bottom,left
    infoWindowOffset: {
      type: String,
      default: 'top'
    },
    // 自定义的弹框内容,支持string或者vue异步组件
    infoWindowContent: {
      type: [String, Object],
      default: null
    }
  },
  watch: {
    isModify (nv) {
      nv ? this.clickOn() : this.clickOff()
    },
    defalutModifyList () {
      this.map.remove(this.modifyArr)
      this.addDefautlModify()
    },
    center () {
      this.center && this.map.setCenter(this.center)
    }
  },
  mounted () {
    !this.center && !this.location && console.warn('建议任选center或location来确认定位,否则只会定位到所在城市中心')
    this.$nextTick(() => this.mapInit())
  },
  methods: {
    // 初始化地图设置(部分设置修改后地图未更新可尝试使用)
    mapInit () {
      AMapBase.then(res => {
        // eslint-disable-next-line no-undef
        this.map = new AMap.Map('container', { resizeEnable: true, zoom: 20 })
        // 根据需求获取定位逻辑
        if (this.location) {
          mapGeolocation(this.map).then(res => {
            console.log(666, res)
            // 默认自身标点
            this.getCenterMarker(res)
            // METHODS:获取定位成功回调事件
            this.$emit('geolocationComplete', res)
          }).catch(rej => {
            console.log(7777, rej)
            // METHODS:获取定位失败回调事件
            this.$emit('eolocationError', rej)
          }).finally(() => {
            this.center && this.map.setCenter(this.center)
          })
        } else {
          this.center && this.map.setCenter(this.center)
        }
        // 根据需求开启点击标记事件
        this.isModify && this.clickOn()
        // 添加默认不可操作标记
        this.defalutModifyList.length && this.addDefautlModify()
      })
    },
    // 获取中心位置并标点
    getCenterMarker (res) {
      if (this.defaultModify && this.maxMarker > this.markerList.length) {
        const opts = {
          lnglat: [res.position.lng, res.position.lat],
          title: res.formattedAddress,
          regeocode: res,
          key: 0 // 点唯一标识符
        }
        const m = setMarker(opts, this.isInfoWindow && this.markerClick, this.dragstart, this.dragend)
        this.markerList.push({ regeocode: opts.regeocode, marker: m, key: opts.key })
        this.map.add(m)
      }
    },
    // 添加不可操作默认标记
    addDefautlModify () {
      this.modifyArr = this.defalutModifyList.map(item => setMarker(item, this.isInfoWindow && this.markerClick))
      this.map.add(this.modifyArr)
    },
    // 开启点击事件
    clickOn () {
      this.map.on('click', this.mapClick)
    },
    // 关闭点击事件
    clickOff () {
      this.map.off('click', this.mapClick)
    },
    // 地图点击事件
    mapClick (data) {
      // console.log('地图点击事件', data)
      // 点击了地图的话确认如果有弹框则关闭弹框
      this.infoWindow && this.infoWindow.close()
      // 地理逆编译保存标记信息
      mapGetAddress([data.lnglat.lng, data.lnglat.lat]).then(res => {
        // console.log('地图点击事件222', res)
        const opts = {
          lnglat: [data.lnglat.lng, data.lnglat.lat],
          title: res.regeocode.formattedAddress,
          regeocode: res.regeocode,
          key: this.markerList.length ? this.markerList[this.markerList.length - 1].key + 1 : 1
        }
        const m = setMarker(opts, this.isInfoWindow && this.markerClick, this.dragstart, this.dragend)
        // 地图选点追加经纬度
        res.regeocode.position = data.lnglat
        const obj = {
          regeocode: res.regeocode,
          marker: m,
          key: opts.key
        }
        this.markerList.push(obj)
        this.map.add(m)
        this.markerClick(opts, m)
        if (this.markerList.length > this.maxMarker) {
          this.map.remove(this.markerList[0].marker)
          this.markerList.shift()
        }
        // METHODS:地址编译后回调成功点击事件
        this.$emit('mapClickOK', data, this.markerList[this.markerList.length - 1], this.markerList)
      }).catch(rej => {
        // METHODS:地址编译后回调失败点击事件
        this.$emit('mapClickErr', data)
        throw (rej)
      })
    },
    // 标记点击信息弹框回调方法
    markerClick (opts, m) {
      console.log(7777, opts, m)
      const data = m && m.getPosition()
      const _this = this
      const template = `<div  style="display: grid;grid-template-areas: '. .';font-size: 14px; "><div style="padding: 0 20px;display: grid;align-content: center;border-right:1px solid #EAEAEA;color:#355DB4 " @click='navigation'>导航</div><div style="padding: 0 20px">${m.getTitle() || opts.title}</div></div>`
      const InfoContent = Vue.extend({
        template,
        methods: {
          navigation () {
            return _this.navigation(opts)
          }
        }
      })
      // eslint-disable-next-line no-mixed-operators
      this.infoWindow = setInfoWindow(this.infoWindowOffset, this.infoWindowContent && (typeof this.infoWindowContent === 'string' ? this.infoWindowContent : this.infoWindowContent.$mount().$el) || new InfoContent().$mount().$el)
      this.infoWindow.open(this.map, data ? [data.lng, data.lat] : opts.lnglat)
    },
    // 标记拖拽开始事件
    dragstart (opts, m) {
      this.infoWindow && this.infoWindow.close()
      for (let i = 0; i < this.markerList.length; i++) {
        // METHODS:标记拖拽开始事件
        return (this.markerList[i].key === opts.key) && this.$emit('dragstart', opts, this.markerList[i])
      }
    },
    // 标记拖拽结束事件
    dragend (opts, m) {
      for (let i = 0; i < this.markerList.length; i++) {
        if (this.markerList[i].key === opts.key) {
          const data = m.getPosition()
          // 拖拽之后动态获取当前拖拽的地址信息
          return mapGetAddress([data.lng, data.lat]
          ).then(res => {
            m.setTitle(res.regeocode.formattedAddress)
            this.markerList[i].marker = m
            this.markerList[i].regeocode = res.regeocode
            opts.title = res.regeocode.formattedAddress
            opts.lnglat = [data.lng, data.lat]
            this.markerClick(opts, m)
            // METHODS:标记拖拽开始事件
            this.$emit('dragend', true, opts, this.markerList[i])
          }).catch(() => this.$emit('dragend', false, opts, this.markerList[i])
          )
        }
      }
    },
    // 点击导航按钮方法
    navigation (data) {
      this.popupShow = true
      this.markerData = data
      // METHODS:点击导航自定义方法
      this.$emit('navigation', data)
    },
    // 调起app导航方法
    popupItemClick (item) {
      openNavigationApp(item.type, this.markerData)
      this.popupShow = false
    }
  }
}
</script>

<style lang="scss">
.map-components {
  width: 100%;
  height: 100%;

  .container-box {
    width: 100%;
    height: 100%;
  }
}
.map-content {
  .map-popup {
    .popup-item {
      //font-weight: bold;
      text-align: center;
      padding: 25px 0;
      background: #ffffff;
      border-bottom: 1px solid #e0e0e0;

      &:last-child {
        border-bottom: none;
      }
    }
  }
}
</style>
